import React, {
  ReactElement,
  useCallback,
  useEffect,
  useMemo,
  useState
} from 'react';
import { View, Text, Image, DeviceEventEmitter } from 'react-native';

import styles from './style';
import Button from '../../../../components/Button';
import {
  updateCurrentPPTWithAnswerState,
  uploadUserInstantAnswer
} from '../../actions';
import { IMPROMPTU_SHADOW_OPTIONS } from '../../../../constant/shadow';
import { instantTime } from '../../../../constant/resource';
import { getUserInfo } from '../../../../store/user';
import { AnswerState } from '../../constant';
import { FinishInstantData, ImpromptuAreaProps } from '../../types';
import { CLASS_ROOM_EVENT_ROLL_CALL_IMPROMPTU } from '../../event';
import { CLASS_FINISH_INSTANT } from '../../../../util/pushMsg';

let timer: NodeJS.Timer | null;
let showResTimer: NodeJS.Timer | null;
let localNeedShowRes: boolean;
let haveSelectedAnswer: boolean;

const clearTimer = (): void => {
  if (timer) {
    clearInterval(timer);
    timer = null;
  }
  if (showResTimer) {
    clearTimeout(showResTimer);
    showResTimer = null;
  }
};

export default (): ReactElement => {
  const [instantAnswerInfo, setInstantAnswerInfo] = useState<
    ImpromptuAreaProps
  >({
    options: [],
    duration: 0,
    title: {
      textStr: '',
      textType: 0
    },
    instantAnswerId: -1,
    startTime: 0,
    isDefault: false,
    answer: ''
  });
  const [showRes, setShowRes] = useState(false);
  const [isCorrect, setIsCorrect] = useState(false);
  const [selectedAnswer, setSelectedAnswer] = useState('');
  const [time, setTime] = useState<number>(0);
  const [width, setWidth] = useState<number>(0);
  const [height, setHeight] = useState<number>(0);

  const {
    options,
    duration,
    title,
    instantAnswerId,
    hideInstantAnswer,
    userId,
    userName,
    show
  } = instantAnswerInfo;

  const { textStr: problem } = title || { textStr: '', textType: 0 };

  const leftAnswer = options.length > 0 && options[0];
  const rightAnswer = options.length > 1 && options[1];

  const { userId: currentUserId } = getUserInfo();
  const canSelected = Number(userId) === Number(currentUserId);

  const onSelectedAnswer = useCallback(
    async (a: string): Promise<void> => {
      if (haveSelectedAnswer) return;
      haveSelectedAnswer = true;

      setSelectedAnswer(a);
      localNeedShowRes = true;
      const { needShowRes, isCorrect: correct } = await uploadUserInstantAnswer(
        a,
        time,
        {
          instantAnswer: instantAnswerInfo,
          show: false
        }
      );
      if (!needShowRes) return;

      updateCurrentPPTWithAnswerState(
        correct ? AnswerState.Right : AnswerState.Wrong
      );

      clearTimer();
      setIsCorrect(!!correct);
      setTimeout((): void => {
        if (!localNeedShowRes) return;
        setShowRes(true);
        showResTimer = setTimeout((): void => {
          if (hideInstantAnswer) {
            hideInstantAnswer();
          }
        }, 2000);
      }, 500);
    },
    [hideInstantAnswer, instantAnswerInfo, time]
  );

  useEffect((): (() => void) => {
    const subscription = DeviceEventEmitter.addListener(
      CLASS_ROOM_EVENT_ROLL_CALL_IMPROMPTU,
      (data: ImpromptuAreaProps): void => {
        setInstantAnswerInfo(data);
      }
    );
    return (): void => {
      if (subscription) {
        subscription.remove();
      }
    };
  }, []);

  useEffect((): (() => void) => {
    const finishInstantSubscription = DeviceEventEmitter.addListener(
      CLASS_FINISH_INSTANT,
      (data: FinishInstantData): void => {
        const {
          userId: submitUserId,
          instantId,
          isCorrect: currentCorrect,
          answer
        } = data;
        if (
          Number(userId) === Number(submitUserId) &&
          Number(instantId) === Number(instantAnswerId)
        ) {
          updateCurrentPPTWithAnswerState(
            currentCorrect ? AnswerState.Right : AnswerState.Wrong
          );
          setIsCorrect(!!currentCorrect);
          setSelectedAnswer(answer);
          setShowRes(true);
          showResTimer = setTimeout((): void => {
            if (hideInstantAnswer) {
              hideInstantAnswer();
            }
          }, 2000);
        }
      }
    );
    return (): void => {
      if (finishInstantSubscription) {
        finishInstantSubscription.remove();
      }
    };
  }, [hideInstantAnswer, instantAnswerId, userId]);

  useEffect((): (() => void) => {
    if (!show) return (): void => {};

    clearTimer();
    setTime(duration / 1000);
    timer = setInterval((): void => {
      let canHideInstant = false;
      setTime((t): number => {
        const resTime = t - 1;
        if (resTime < 0) {
          canHideInstant = true;
          clearTimer();
          return t;
        }
        return resTime;
      });
      if (canHideInstant && hideInstantAnswer) {
        hideInstantAnswer();
      }
    }, 1000);
    return (): void => {
      localNeedShowRes = false;
      haveSelectedAnswer = false;
      clearTimer();
      setShowRes(false);
      setIsCorrect(false);
      setSelectedAnswer('');
    };
  }, [duration, hideInstantAnswer, instantAnswerId, show]);

  const getResStyleWithAnswer = useCallback(
    (a: string): any => {
      let resStyle;
      if (!showRes) return resStyle;

      if (isCorrect) {
        if (selectedAnswer === a) {
          resStyle = styles.correctAnswer;
        }
        return resStyle;
      }

      if (selectedAnswer === a) {
        resStyle = styles.wrongAnswer;
      } else {
        resStyle = styles.correctAnswer;
      }
      return resStyle;
    },
    [isCorrect, selectedAnswer, showRes]
  );

  return useMemo((): ReactElement => {
    const haveProblem = problem && problem.length > 0;
    const leftResStyle = getResStyleWithAnswer(leftAnswer || '');
    const rightResStyle = getResStyleWithAnswer(rightAnswer || '');
    if (!show) return <View />;
    return (
      <View style={styles.container}>
        <View style={styles.shadowContainer}>
          {width > 0 && height > 0 && (
            <Button
              needSVGShadow
              shadowStyle={[styles.shadow, { width, height }]}
              shadowOptions={IMPROMPTU_SHADOW_OPTIONS}
              style={[styles.content, { width, height }]}
              activity={false}
            />
          )}
          <View
            style={[
              styles.shadowContent,
              haveProblem ? styles.haveProblem : {}
            ]}
            onLayout={(e): void => {
              const { width: w, height: h } = e.nativeEvent.layout;
              setWidth(w);
              setHeight(h);
            }}
          >
            <View style={styles.leftContent}>
              <View style={styles.timeContent}>
                <Image
                  style={styles.timeIcon}
                  source={instantTime}
                  resizeMode="contain"
                />
                <Text style={styles.timeDesc}>{time}</Text>
              </View>
              <Text style={styles.problem}>
                <Text style={styles.name}>@{userName}: </Text>
                {problem}
              </Text>
            </View>
            <View style={styles.rightContent}>
              {leftAnswer && (
                <Button
                  style={[
                    styles.answer,
                    haveProblem ? styles.haveProblemAnswer : {},
                    leftResStyle
                  ]}
                  onPress={(): void => {
                    onSelectedAnswer(leftAnswer);
                  }}
                  hitSlop={{ left: 20, top: 20, right: 0, bottom: 20 }}
                  activity={canSelected}
                >
                  <Text
                    style={[
                      styles.answerDesc,
                      leftResStyle ? {} : styles.blackDesc
                    ]}
                  >
                    {leftAnswer}
                  </Text>
                  {selectedAnswer === leftAnswer && !showRes ? (
                    <View style={styles.selectedAnswer} />
                  ) : null}
                </Button>
              )}
              {rightAnswer && (
                <Button
                  style={[
                    styles.answer,
                    styles.rightAnswer,
                    haveProblem ? styles.haveProblemAnswer : {},
                    rightResStyle
                  ]}
                  onPress={(): void => {
                    onSelectedAnswer(rightAnswer);
                  }}
                  hitSlop={{ left: 0, top: 20, right: 20, bottom: 20 }}
                  activity={canSelected}
                >
                  <Text
                    style={[
                      styles.answerDesc,
                      rightResStyle ? {} : styles.blackDesc
                    ]}
                  >
                    {rightAnswer}
                  </Text>
                  {selectedAnswer === rightAnswer && !showRes ? (
                    <View style={styles.selectedAnswer} />
                  ) : null}
                </Button>
              )}
            </View>
          </View>
        </View>
        <View style={styles.doProblem}>
          <Text>{`${userName}正在上台做题...`}</Text>
        </View>
      </View>
    );
  }, [
    canSelected,
    getResStyleWithAnswer,
    height,
    leftAnswer,
    onSelectedAnswer,
    problem,
    rightAnswer,
    selectedAnswer,
    show,
    showRes,
    time,
    userName,
    width
  ]);
};
